[IA64] Handle MMIO EFI mappings outside the page table range
authorawilliam@xenbuild2.aw <awilliam@xenbuild2.aw>
Thu, 1 Mar 2007 18:21:44 +0000 (11:21 -0700)
committerawilliam@xenbuild2.aw <awilliam@xenbuild2.aw>
Thu, 1 Mar 2007 18:21:44 +0000 (11:21 -0700)
We cannot rely on MMIO pages presented in the EFI mem-map can be
mapped directly to the same meta-physical address, because of
restrictions on the address range imposed by the page tables.

As an example, IO ports are located at 0x1ffffffffc000000 on many SN2
systems.

Change assign_domain_mmio_page() to take a flags and a source and
destination address to handle this and catch IO ports above
0x1ffffffff0000000 and map them down to a safe area.

Signed-off-by: Jes Sorensen <jes@sgi.com>
xen/arch/ia64/xen/dom0_ops.c
xen/arch/ia64/xen/dom_fw.c
xen/arch/ia64/xen/mm.c
xen/include/asm-ia64/mm.h

index 52c3745f8795fba9f7cc5baaa2fdff29c059f5e6..d20170150f34ee7005e76d2cb487d428c229a0b3 100644 (file)
@@ -299,13 +299,17 @@ dom0vp_ioremap(struct domain *d, unsigned long mpaddr, unsigned long size)
     if (size == 0)
         size = PAGE_SIZE;
 
+    if (size == 0)
+        printk(XENLOG_WARNING "ioremap(): Trying to map %lx, size 0\n", mpaddr);
+
     end = PAGE_ALIGN(mpaddr + size);
 
     if (!iomem_access_permitted(d, mpaddr >> PAGE_SHIFT,
                                 (end >> PAGE_SHIFT) - 1))
         return -EPERM;
 
-    return assign_domain_mmio_page(d, mpaddr, size);
+    return assign_domain_mmio_page(d, mpaddr, mpaddr, size,
+                                   ASSIGN_writable | ASSIGN_nocache);
 }
 
 unsigned long
index c69ab89c80d455b84f65518428bcfdff95549b85..7402d3f77b4f5caa2f9cbea4bd73fa72d341de91 100644 (file)
@@ -534,6 +534,7 @@ complete_dom0_memmap(struct domain *d,
                u64 start = md->phys_addr;
                u64 size = md->num_pages << EFI_PAGE_SHIFT;
                u64 end = start + size;
+               u64 mpaddr;
                unsigned long flags;
 
                switch (md->type) {
@@ -566,10 +567,22 @@ complete_dom0_memmap(struct domain *d,
                        break;
 
                case EFI_MEMORY_MAPPED_IO_PORT_SPACE:
+                       flags = ASSIGN_writable;        /* dummy - zero */
+                       if (md->attribute & EFI_MEMORY_UC)
+                               flags |= ASSIGN_nocache;
+
+                       if (start > 0x1ffffffff0000000UL) {
+                               mpaddr = 0x4000000000000UL - size;
+                               printk(XENLOG_INFO "Remapping IO ports from "
+                                      "%lx to %lx\n", start, mpaddr);
+                       } else
+                               mpaddr = start;
+
                        /* Map into dom0.  */
-                       assign_domain_mmio_page(d, start, size);
+                       assign_domain_mmio_page(d, mpaddr, start, size, flags);
                        /* Copy descriptor.  */
                        *dom_md = *md;
+                       dom_md->phys_addr = mpaddr;
                        dom_md->virt_addr = 0;
                        num_mds++;
                        break;
@@ -652,8 +665,12 @@ complete_dom0_memmap(struct domain *d,
                if (domain_page_mapped(d, addr))
                        continue;
                
-               if (efi_mmio(addr, PAGE_SIZE))
-                       assign_domain_mmio_page(d, addr, PAGE_SIZE);
+               if (efi_mmio(addr, PAGE_SIZE)) {
+                       unsigned long flags;
+                       flags = ASSIGN_writable | ASSIGN_nocache;
+                       assign_domain_mmio_page(d, addr, addr,
+                                               PAGE_SIZE, flags);
+               }
        }
        return num_mds;
 }
index b1efa6293facc3118dbb6e3fb4f23374c6c1e279..9ce2c34949050b1e703de5313a6d51d5a87c4f62 100644 (file)
@@ -1044,9 +1044,11 @@ efi_mmio(unsigned long physaddr, unsigned long size)
 }
 
 unsigned long
-assign_domain_mmio_page(struct domain *d,
-                        unsigned long mpaddr, unsigned long size)
+assign_domain_mmio_page(struct domain *d, unsigned long mpaddr,
+                        unsigned long phys_addr, unsigned long size,
+                        unsigned long flags)
 {
+    unsigned long end = PAGE_ALIGN(mpaddr + size);
     if (size == 0) {
         gdprintk(XENLOG_INFO, "%s: domain %p mpaddr 0x%lx size = 0x%lx\n",
                 __func__, d, mpaddr, size);
@@ -1058,7 +1060,12 @@ assign_domain_mmio_page(struct domain *d,
 #endif
         return -EINVAL;
     }
-    assign_domain_same_page(d, mpaddr, size, ASSIGN_writable | ASSIGN_nocache);
+
+    for (mpaddr &= PAGE_MASK; mpaddr < end;
+         mpaddr += PAGE_SIZE, phys_addr += PAGE_SIZE) {
+        __assign_domain_page(d, mpaddr, phys_addr, flags);
+    }
+
     return mpaddr;
 }
 
index a232bd599c3b6d470bfcafefabbb333ad16f7783..944775aae5b752fb0c952aca0d51ee895ade29f5 100644 (file)
@@ -433,7 +433,7 @@ struct p2m_entry;
 extern unsigned long lookup_domain_mpa(struct domain *d, unsigned long mpaddr, struct p2m_entry* entry);
 extern void *domain_mpa_to_imva(struct domain *d, unsigned long mpaddr);
 extern volatile pte_t *lookup_noalloc_domain_pte(struct domain* d, unsigned long mpaddr);
-extern unsigned long assign_domain_mmio_page(struct domain *d, unsigned long mpaddr, unsigned long size);
+extern unsigned long assign_domain_mmio_page(struct domain *d, unsigned long mpaddr, unsigned long phys_addr, unsigned long size, unsigned long flags);
 extern unsigned long assign_domain_mach_page(struct domain *d, unsigned long mpaddr, unsigned long size, unsigned long flags);
 int domain_page_mapped(struct domain *d, unsigned long mpaddr);
 int efi_mmio(unsigned long physaddr, unsigned long size);